{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "7e883688",
   "metadata": {},
   "source": [
    "# 런타임에 체인 내부 구성하기\n",
    "\n",
    "이번 튜토리얼은 Chain 을 호출시 다양한 옵션을 동적으로 설정할 수 있는 방법을 알아보겠습니다.\n",
    "\n",
    "다음의 2가지 방식으로 동적 구성을 할 수 있습니다.\n",
    "\n",
    "- 첫째, `configurable_fields` 메서드입니다. 이 메서드를 통해 실행 가능한 객체의 특정 필드를 구성할 수 있습니다.\n",
    "\n",
    "- 둘째, `configurable_alternatives` 메서드입니다. 이 메서드를 사용하면 런타임 중에 설정할 수 있는 특정 실행 가능한 객체에 대한 대안을 나열할 수 있습니다.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6374b0f3",
   "metadata": {},
   "source": [
    "## configurable_fields\n",
    "\n",
    "`configurable_fields` 는 시스템의 설정 값을 정의하는 필드를 의미합니다."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "367696ff",
   "metadata": {},
   "source": [
    "## 동적 속성 지정\n",
    "\n",
    "`ChatOpenAI` 을 사용할 때, 우리는 `model_name` 와 같은 설정을 조정할 수 있습니다.\n",
    "\n",
    "`model_name` 은 GPT 의 버전을 명시할 때 사용하는 속성입니다. 예를 들어, `gpt-4o`, `gpt-4o-mini` 등을 설정하여 모델을 선택할 수 있습니다.\n",
    "\n",
    "만약, 고정된 `model_name` 이 아닌 동적으로 모델을 지정하고 싶을 때는 다음과 같이 `ConfigurableField` 를 활용하여 동적으로 설정할 수 있는 속성 값으로 변환할 수 있습니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "94943a42",
   "metadata": {},
   "outputs": [],
   "source": [
    "# API 키를 환경변수로 관리하기 위한 설정 파일\n",
    "from dotenv import load_dotenv\n",
    "\n",
    "# API 키 정보 로드\n",
    "load_dotenv()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "01429ce7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# LangSmith 추적을 설정합니다. https://smith.langchain.com\n",
    "# !pip install langchain-teddynote\n",
    "from langchain_teddynote import logging\n",
    "\n",
    "# 프로젝트 이름을 입력합니다.\n",
    "logging.langsmith(\"CH13-LCEL-Advanced\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c6bf0b7b",
   "metadata": {},
   "source": [
    "`configurable_fields` 메서드를 사용하여 `model_name` 속성을 동적 구성 가능한 필드로 지정합니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "33265c7e",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.prompts import PromptTemplate\n",
    "from langchain_core.runnables import ConfigurableField\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "model = ChatOpenAI(temperature=0, model_name=\"gpt-4o\")\n",
    "\n",
    "model.invoke(\"대한민국의 수도는 어디야?\").__dict__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7edb87cd",
   "metadata": {},
   "outputs": [],
   "source": [
    "model = ChatOpenAI(temperature=0).configurable_fields(\n",
    "    model_name=ConfigurableField(  # model_name 은 원래 ChatOpenAI 의 필드입니다.\n",
    "        id=\"gpt_version\",  # model_name 의 id 를 설정합니다.\n",
    "        name=\"Version of GPT\",  # model_name 의 이름을 설정합니다.\n",
    "        # model_name 의 설명을 설정합니다.\n",
    "        description=\"Official model name of GPTs. ex) gpt-4o, gpt-4o-mini\",\n",
    "    )\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cc5d51db",
   "metadata": {},
   "source": [
    "`model.invoke()` 호출시 `config={\"configurable\": {\"키\": \"값\"}}` 형식으로 동적 지정할 수 있습니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c41cf11f",
   "metadata": {},
   "outputs": [],
   "source": [
    "model.invoke(\n",
    "    \"대한민국의 수도는 어디야?\",\n",
    "    # gpt_version 을 gpt-3.5-turbo 로 설정합니다.\n",
    "    config={\"configurable\": {\"gpt_version\": \"gpt-3.5-turbo\"}},\n",
    ").__dict__"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2e033a23",
   "metadata": {},
   "source": [
    "이번에는 `gpt-4o-mini` 모델을 사용해보겠습니다. 출력에 바뀐 모델을 확인하세요.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fd831aa4",
   "metadata": {},
   "outputs": [],
   "source": [
    "model.invoke(\n",
    "    # gpt_version 을 gpt-4o-mini 로 설정합니다.\n",
    "    \"대한민국의 수도는 어디야?\",\n",
    "    config={\"configurable\": {\"gpt_version\": \"gpt-4o-mini\"}},\n",
    ").__dict__"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fdc33652",
   "metadata": {},
   "source": [
    "`model` 객체의 `with_config()` 메서드를 사용하여 `configurable` 매개변수를 설정할 수도 있습니다. 이전과 동작하는 방식은 동일합니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4424994d",
   "metadata": {},
   "outputs": [],
   "source": [
    "model.with_config(configurable={\"gpt_version\": \"gpt-4o-mini\"}).invoke(\n",
    "    \"대한민국의 수도는 어디야?\"\n",
    ").__dict__"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e7df5a97",
   "metadata": {},
   "source": [
    "또한 이 함수를 체인의 일부로 사용할 때에도 동일한 방식으로 활용할 수 있습니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b3b8d6dd",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 템플릿에서 프롬프트 템플릿을 생성합니다.\n",
    "prompt = PromptTemplate.from_template(\"{x} 보다 큰 위의 난수를 선택합니다.\")\n",
    "chain = (\n",
    "    prompt | model\n",
    ")  # 프롬프트와 모델을 연결하여 체인을 생성합니다. 프롬프트의 출력이 모델의 입력으로 전달됩니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "68305e18",
   "metadata": {},
   "outputs": [],
   "source": [
    "chain.invoke({\"x\": 0}).__dict__  # 체인을 호출하고 입력 변수 \"x\"에 0을 전달합니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3de127df",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 체인을 호출할 때 설정을 지정하여 체인을 호출할 수 있습니다.\n",
    "chain.with_config(configurable={\"gpt_version\": \"gpt-4o\"}).invoke({\"x\": 0}).__dict__"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9bf79605",
   "metadata": {},
   "source": [
    "## HubRunnable: LangChain Hub의 설정 변경\n",
    "\n",
    "`HubRunnable` 을 사용하면 Hub 에 등록된 프롬프트의 전환을 용이하게 합니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "45dcb480",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.runnables.hub import HubRunnable\n",
    "\n",
    "prompt = HubRunnable(\"teddynote/rag-prompt-korean\").configurable_fields(\n",
    "    # 소유자 저장소 커밋을 설정하는 ConfigurableField\n",
    "    owner_repo_commit=ConfigurableField(\n",
    "        # 필드의 ID\n",
    "        id=\"hub_commit\",\n",
    "        # 필드의 이름\n",
    "        name=\"Hub Commit\",\n",
    "        # 필드에 대한 설명\n",
    "        description=\"Korean RAG prompt by teddynote\",\n",
    "    )\n",
    ")\n",
    "prompt"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "620e8eeb",
   "metadata": {},
   "source": [
    "별도의 `with_config` 지정 없이 `prompt.invoke()` 메서드를 호출하면 처음 설정한 `\"rlm/rag-prompt\"` hub 에 등록된 프롬프트를 pull 하여 가져옵니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3694b368",
   "metadata": {},
   "outputs": [],
   "source": [
    "# prompt 객체의 invoke 메서드를 호출하여 \"question\"과 \"context\" 매개변수를 전달합니다.\n",
    "prompt.invoke({\"question\": \"Hello\", \"context\": \"World\"}).messages"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3f54b476",
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt.with_config(\n",
    "    # hub_commit 을 teddynote/simple-summary-korean 으로 설정합니다.\n",
    "    configurable={\"hub_commit\": \"teddynote/simple-summary-korean\"}\n",
    ").invoke({\"context\": \"Hello\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b570a059",
   "metadata": {},
   "source": [
    "## Configurable Alternatives: Runnable 객체 자체의 대안 설정\n",
    "\n",
    "런타임에 설정할 수 있는 Runnable 에 대한 대안을 구성합니다.\n",
    "\n",
    "**구성 가능한 대안들**\n",
    "\n",
    "`ChatAnthropic` 의 구성 가능한 언어 모델은 다양한 작업과 컨텍스트에 적용할 수 있는 유연성을 제공합니다.\n",
    "\n",
    "동적으로 설정(Config) 값을 변경하기 위하여 모델에 설정하는 파라미터를 ConfigurableField 객체로 설정합니다.\n",
    "\n",
    "- `model`: 사용할 기본 언어 모델을 지정합니다.\n",
    "\n",
    "- `temperature`: 0에서 1 사이의 값으로, 샘플링의 무작위성을 제어합니다. 값이 낮을수록 더 결정적이고 반복적인 출력이 생성되며, 값이 높을수록 더 다양하고 창의적인 출력이 생성됩니다."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c90d5be2",
   "metadata": {},
   "source": [
    "### LLM 객체의 대안(alternatives) 설정 방법\n",
    "\n",
    "LLM(Large Language Model)을 활용하여 이를 수행하는 방법을 살펴보겠습니다.\n",
    "\n",
    "[참고]\n",
    "\n",
    "- `ChatAnthropic` 모델을 사용하기 위하여 API KEY를 발급받아 설정해야합니다.\n",
    "- 링크: https://console.anthropic.com/dashboard\n",
    "- 아래 주석을 해제하고 API KEY를 설정하거나, `.env` 파일에 설정합니다.\n",
    "  \n",
    "`ANTHROPIC_API_KEY` 환경변수를 설정합니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2d3892fe",
   "metadata": {},
   "outputs": [],
   "source": [
    "# import os\n",
    "\n",
    "# os.environ[\"ANTHROPIC_API_KEY\"] = \"ANTHROPIC API KEY를 입력합니다.\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2969a0e2",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.prompts import PromptTemplate\n",
    "from langchain_anthropic import ChatAnthropic\n",
    "from langchain_core.runnables import ConfigurableField\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "llm = ChatAnthropic(\n",
    "    temperature=0, model=\"claude-3-5-sonnet-20240620\"\n",
    ").configurable_alternatives(\n",
    "    # 이 필드에 id를 부여합니다.\n",
    "    # 최종 실행 가능한 객체를 구성할 때, 이 id를 사용하여 이 필드를 구성할 수 있습니다.\n",
    "    ConfigurableField(id=\"llm\"),\n",
    "    # 기본 키를 설정합니다.\n",
    "    # 이 키를 지정하면 위에서 초기화된 기본 LLM(ChatAnthropic)이 사용됩니다.\n",
    "    default_key=\"anthropic\",\n",
    "    # 'openai'라는 이름의 새 옵션을 추가하며, 이는 `ChatOpenAI()`와 동일합니다.\n",
    "    openai=ChatOpenAI(model=\"gpt-4o-mini\"),\n",
    "    # 'gpt4'라는 이름의 새 옵션을 추가하며, 이는 `ChatOpenAI(model=\"gpt-4\")`와 동일합니다.\n",
    "    gpt4o=ChatOpenAI(model=\"gpt-4o\"),\n",
    "    # 여기에 더 많은 구성 옵션을 추가할 수 있습니다.\n",
    ")\n",
    "prompt = PromptTemplate.from_template(\"{topic} 에 대해 간단히 설명해주세요.\")\n",
    "chain = prompt | llm"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e86d70d5",
   "metadata": {},
   "source": [
    "`chain.invoke()` 메서드를 기본 LLM 인 `ChatAnthropic` 을 활용한 체인을 호출합니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "23a7007a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Anthropic을 기본으로 호출합니다.\n",
    "chain.invoke({\"topic\": \"뉴진스\"}).__dict__"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "78a94820",
   "metadata": {},
   "source": [
    "`chain.with_config(configurable={\"llm\": \"모델\"})`를 사용하여 사용할 `llm`으로 다른 모델을 지정할 수 있습니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "12caa595",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 체인의 설정을 변경하여 호출합니다.\n",
    "chain.with_config(configurable={\"llm\": \"openai\"}).invoke({\"topic\": \"뉴진스\"}).__dict__"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "65dd452b",
   "metadata": {},
   "source": [
    "체인의 설정을 변경하여 사용할 언어 모델을 `gpt4o` 로 지정합니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ae6c380c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 체인의 설정을 변경하여 호출합니다.\n",
    "chain.with_config(configurable={\"llm\": \"gpt4o\"}).invoke({\"topic\": \"뉴진스\"}).__dict__"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "50910428",
   "metadata": {},
   "source": [
    "체인의 설정을 변경하여 사용할 언어 모델을 `anthropic` 로 지정합니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "27c7a34b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 체인의 설정을 변경하여 호출합니다.\n",
    "chain.with_config(configurable={\"llm\": \"anthropic\"}).invoke(\n",
    "    {\"topic\": \"뉴진스\"}\n",
    ").__dict__"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0b2e2390",
   "metadata": {},
   "source": [
    "## 프롬프트의 대안 설정 방법\n",
    "\n",
    "프롬프트도 이전의 LLM 대안 설정 방법과 유사한 작업을 수행할 수 있습니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4310ba20",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 언어 모델을 초기화하고 temperature를 0으로 설정합니다.\n",
    "llm = ChatOpenAI(temperature=0)\n",
    "\n",
    "prompt = PromptTemplate.from_template(\n",
    "    \"{country} 의 수도는 어디야?\"  # 기본 프롬프트 템플릿\n",
    ").configurable_alternatives(\n",
    "    # 이 필드에 id를 부여합니다.\n",
    "    ConfigurableField(id=\"prompt\"),\n",
    "    # 기본 키를 설정합니다.\n",
    "    default_key=\"capital\",\n",
    "    # 'area'이라는 새로운 옵션을 추가합니다.\n",
    "    area=PromptTemplate.from_template(\"{country} 의 면적은 얼마야?\"),\n",
    "    # 'population'이라는 새로운 옵션을 추가합니다.\n",
    "    population=PromptTemplate.from_template(\"{country} 의 인구는 얼마야?\"),\n",
    "    # 'eng'이라는 새로운 옵션을 추가합니다.\n",
    "    eng=PromptTemplate.from_template(\"{input} 을 영어로 번역해주세요.\"),\n",
    "    # 여기에 더 많은 구성 옵션을 추가할 수 있습니다.\n",
    ")\n",
    "\n",
    "# 프롬프트와 언어 모델을 연결하여 체인을 생성합니다.\n",
    "chain = prompt | llm"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d7f69fb1",
   "metadata": {},
   "source": [
    "아무런 설정 변경이 없다면 기본 프롬프트가 입력됩니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f52eb9b3",
   "metadata": {},
   "outputs": [],
   "source": [
    "# config 변경 없이 체인을 호출합니다.\n",
    "chain.invoke({\"country\": \"대한민국\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ccd2deea",
   "metadata": {},
   "source": [
    "`with_config` 로 다른 프롬프트를 호출합니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b3c23a30",
   "metadata": {},
   "outputs": [],
   "source": [
    "# with_config 로 체인의 설정을 변경하여 호출합니다.\n",
    "chain.with_config(configurable={\"prompt\": \"area\"}).invoke({\"country\": \"대한민국\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ce1058b6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# with_config 로 체인의 설정을 변경하여 호출합니다.\n",
    "chain.with_config(configurable={\"prompt\": \"population\"}).invoke({\"country\": \"대한민국\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "01a5de8f",
   "metadata": {},
   "source": [
    "이번에는 `eng` 프롬프트를 사용하여 번역을 요청합니다. 이때 전달할 입력 변수는 `input`입니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a7c224ca",
   "metadata": {},
   "outputs": [],
   "source": [
    "# with_config 로 체인의 설정을 변경하여 호출합니다.\n",
    "chain.with_config(configurable={\"prompt\": \"eng\"}).invoke({\"input\": \"사과는 맛있어!\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7698baad",
   "metadata": {},
   "source": [
    "## 프롬프트 & LLM 모두 변경\n",
    "\n",
    "프롬프트와 LLM을 사용하여 여러 가지 사항을 구성할 수 있습니다.\n",
    "\n",
    "다음은 프롬프트와 LLM을 모두 사용하여 이를 수행하는 예시입니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "caa872fe",
   "metadata": {},
   "outputs": [],
   "source": [
    "llm = ChatAnthropic(\n",
    "    temperature=0, model=\"claude-3-5-sonnet-20240620\"\n",
    ").configurable_alternatives(\n",
    "    # 이 필드에 id를 부여합니다.\n",
    "    # 최종 실행 가능한 객체를 구성할 때, 이 id를 사용하여 이 필드를 구성할 수 있습니다.\n",
    "    ConfigurableField(id=\"llm\"),\n",
    "    # 기본 키를 설정합니다.\n",
    "    # 이 키를 지정하면 위에서 초기화된 기본 LLM(ChatAnthropic)이 사용됩니다.\n",
    "    default_key=\"anthropic\",\n",
    "    # 'openai'라는 이름의 새 옵션을 추가하며, 이는 `ChatOpenAI(model=\"gpt-4o-mini\")`와 동일합니다.\n",
    "    openai=ChatOpenAI(model=\"gpt-4o-mini\"),\n",
    "    # 'gpt4'라는 이름의 새 옵션을 추가하며, 이는 `ChatOpenAI(model=\"gpt-4o\")`와 동일합니다.\n",
    "    gpt4=ChatOpenAI(model=\"gpt-4o\"),\n",
    "    # 여기에 더 많은 구성 옵션을 추가할 수 있습니다.\n",
    ")\n",
    "\n",
    "prompt = PromptTemplate.from_template(\n",
    "    \"{company} 에 대해서 20자 이내로 설명해 줘.\"  # 기본 프롬프트 템플릿\n",
    ").configurable_alternatives(\n",
    "    # 이 필드에 id를 부여합니다.\n",
    "    ConfigurableField(id=\"prompt\"),\n",
    "    # 기본 키를 설정합니다.\n",
    "    default_key=\"description\",\n",
    "    # 'founder'이라는 새로운 옵션을 추가합니다.\n",
    "    founder=PromptTemplate.from_template(\"{company} 의 창립자는 누구인가요?\"),\n",
    "    # 'competitor'이라는 새로운 옵션을 추가합니다.\n",
    "    competitor=PromptTemplate.from_template(\"{company} 의 경쟁사는 누구인가요?\"),\n",
    "    # 여기에 더 많은 구성 옵션을 추가할 수 있습니다.\n",
    ")\n",
    "chain = prompt | llm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "503397e0",
   "metadata": {},
   "outputs": [],
   "source": [
    "# with_config 로 설정 값을 지정하여 구성할 수 있습니다.\n",
    "chain.with_config(configurable={\"prompt\": \"founder\", \"llm\": \"openai\"}).invoke(\n",
    "    # 사용자가 제공한 회사에 대한 처리를 요청합니다.\n",
    "    {\"company\": \"애플\"}\n",
    ").__dict__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "801a4dd6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 하나만 구성하려는 경우\n",
    "chain.with_config(configurable={\"llm\": \"anthropic\"}).invoke(\n",
    "    {\"company\": \"애플\"}\n",
    ").__dict__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "730b47ef",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 하나만 구성하려는 경우\n",
    "chain.with_config(configurable={\"prompt\": \"competitor\"}).invoke(\n",
    "    {\"company\": \"애플\"}\n",
    ").__dict__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bacd5148",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 하나만 구성하려는 경우\n",
    "chain.invoke({\"company\": \"애플\"}).__dict__"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3da3f649",
   "metadata": {},
   "source": [
    "## 설정 저장\n",
    "\n",
    "구성된 체인을 별도의 객체로 쉽게 저장할 수 있습니다. 예를 들어, 특정 작업을 위해 사용자 정의된 체인을 구성한 후, 이를 재사용 가능한 객체로 저장함으로써 향후 유사한 작업에서 손쉽게 활용할 수 있습니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "75d4c110",
   "metadata": {},
   "outputs": [],
   "source": [
    "# with_config 로 설정을 변경하여 생성한 체인을 별도의 변수에 저장합니다.\n",
    "gpt4_competitor_chain = chain.with_config(\n",
    "    configurable={\"llm\": \"gpt4\", \"prompt\": \"competitor\"}\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1038dd36",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 체인을 호출합니다.\n",
    "gpt4_competitor_chain.invoke({\"company\": \"애플\"}).__dict__"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "py-test",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
